package com.zhouheng.springbootmultithreading.tuling.sync;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Fox
 * <p>
 * 根据QMode的不同，会执行不同的唤醒策略
 * 管程，Monitor机制在java中的实现ObjectMonitor
 * MESA模型
 * cxq entryList两个入口等待队列
 * 一个条件阻塞队列
 * <p>
 * // 1.演示线程A释放锁，线程B执行后释放锁时，线程A和线程C谁先获得锁
 * 执行效果会先唤醒线程A，再线程C获取到锁
 * 原因线程A 调用wait阻塞时，放到entryList的，线程C放到cxq里的
 * 如果entryList不为空，会先唤醒entryList的
 * // 2.演示线程A获取锁，线程B和线程C同时等待，线程B和线程C在线程A执行完后谁先获得锁
 * 演示时，注释到线程A的lock.wait(300);代码
 * 执行效果，C先于B得到锁
 * 原因，线程B,C阻塞时在cxq的，但是entryList为null，会将cxq的挪到entryList，导致先进的后出
 */
@Slf4j
public class SyncQModeDemo {

    public static void main(String[] args) throws InterruptedException {
        SyncQModeDemo demo = new SyncQModeDemo();
        demo.startThreadA();
        //控制线程执行时间
        Thread.sleep(100);
        demo.startThreadB();
        Thread.sleep(100);
        demo.startThreadC();
    }

    final Object lock = new Object();

    public void startThreadA() {
        new Thread(() -> {
            synchronized (lock) {
                log.debug("A get lock");
                try {
                    Thread.sleep(300);
                    lock.wait(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("A release lock");
            }
        }, "thread-A").start();
    }

    public void startThreadB() {
        new Thread(() -> {
            synchronized (lock) {
                try {
                    log.debug("B get lock");
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.debug("B release lock");
            }
        }, "thread-B").start();
    }

    public void startThreadC() {
        new Thread(() -> {
            synchronized (lock) {

                log.debug("C get lock");
            }
        }, "thread-C").start();
    }

}
